/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package pt.utl.ist.isr.livetrack.ui;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GridBagLayout;
import java.awt.font.FontRenderContext;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Map.Entry;
import java.util.Timer;
import java.util.TimerTask;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JPanel;
import org.openide.util.Exceptions;
import pt.utl.ist.isr.livetrack.server.LTServer;
import pt.utl.ist.isr.livetrack.server.interfaces.Blob;
import pt.utl.ist.isr.livetrack.server.interfaces.Camera;

/**
 *
 * @author David Miguel Antunes <davidmiguel [ at ] antunes.net>
 */
public class CameraView extends JPanel implements CameraViewController.CameraViewControllerObserver {

    private static final Logger logger = Logger.getLogger(CameraView.class.getName());
    private TimerTask displayTask = new TimerTask() {

        @Override
        public void run() {
            if (CameraView.this.isShowing()) {
                try {
                    byte[] byteArray = null;
                    CameraViewController.DisplayType displayType = controller.getDisplayType();
                    switch (displayType) {
                        case ACQUIRED:
                            byteArray = camera.getImageAsByteArray();
                            break;
                        case SUBTRACTED:
                            byteArray = camera.getSubtractedAsByteArray();
                            break;
                        case BINARY:
                            byteArray = camera.getBinaryAsByteArray();
                            break;
                        case BACKGROUND:
                            byteArray = camera.getBackgroundAsByteArray();
                            break;
                        default:
                            byteArray = camera.getImageAsByteArray();
                            break;
                    }
                    if (byteArray != null) {
                        imageLabel.setText("");
                        img = ImageIO.read(new ByteArrayInputStream(byteArray));

                        if (controller.isHighlightBlobsEnabled()) {
                            if (controller.getDisplayType().equals(CameraViewController.DisplayType.BINARY)) {
                                BufferedImage newImg = new BufferedImage(img.getWidth(), img.getHeight(), BufferedImage.TYPE_INT_RGB);
                                newImg.getGraphics().drawImage(img, 0, 0, null);
                                img = newImg;
                            }
                            Graphics g = img.getGraphics();
                            g.setColor(Color.red);
                            ArrayList<Blob> blobs = camera.getBlobs();
                            if (blobs != null) {
                                for (Blob blob : blobs) {
                                    g.drawRect(
                                            blob.getTopLeftX(),
                                            blob.getTopLeftY(),
                                            blob.getBottomRightX() - blob.getTopLeftX(),
                                            blob.getBottomRightY() - blob.getTopLeftY());
                                }
                            }
                            if (controller.isTrackerOutputEnabled() && server.getTracker().isRunning()) {
                                for (Entry<Long, Blob> entry : server.getTracker().getTargets().entrySet()) {

                                    if (entry.getValue().getCameraId().equals(camera.getId())) {
                                        g.setColor(Color.white);
                                        g.fillRect(
                                                entry.getValue().getTopLeftX(),
                                                entry.getValue().getTopLeftY() - g.getFontMetrics(g.getFont()).getHeight() + 4,
                                                g.getFontMetrics(g.getFont()).stringWidth("" + entry.getKey()) + 5,
                                                g.getFontMetrics(g.getFont()).getHeight() + 2);

                                        g.setColor(Color.black);
                                        g.drawString(
                                                "" + entry.getKey(),
                                                entry.getValue().getTopLeftX(),
                                                entry.getValue().getTopLeftY());
                                    }
                                }
                            }
                        }
                        if (controller.isRoiEnabled()) {
                            Graphics g = img.getGraphics();
                            switch (camera.getRoiType()) {
                                case ACCEPT:
                                    g.setColor(new Color(0f, 1f, 0f, 0.5f));
                                    break;
                                case REJECT:
                                    g.setColor(new Color(1f, 0f, 0f, 0.5f));
                                    break;
                                case DISABLED:
                                    g.setColor(new Color(0.5f, 0.5f, 0.5f, 0.5f));
                                    break;
                            }
                            Rectangle2D roi = camera.getRoi();
                            g.fillRect(
                                    (int) roi.getX(),
                                    (int) roi.getY(),
                                    (int) roi.getWidth(),
                                    (int) roi.getHeight());
                        }
                        updateImage();
                    } else {
                        imageLabel.setIcon(null);
                        imageLabel.setText("No image available.");
                    }
                } catch (IOException ex) {
                    Exceptions.printStackTrace(ex);
                }
            }
        }
    };
    private Timer displayTaskTimer = new Timer();
    private Camera camera;
    private LTServer server;
    private CameraViewController controller;
    private JLabel imageLabel;
    private boolean scale = false;
    private int width = -1;
    private BufferedImage img;

    public CameraView(LTServer server, Camera camera, CameraViewController controller, int updatePeriod) {
        this.camera = camera;
        this.server = server;
        this.controller = controller;
        imageLabel = new JLabel();
        displayTaskTimer.schedule(displayTask, 0, updatePeriod);
        controller.getObservers().add(this);
        this.setLayout(new GridBagLayout());
        this.add(imageLabel);
    }

    public CameraView(LTServer server, Camera camera, CameraViewController controller) {
        this(server, camera, controller, 60);
    }

    private void updateImage() {
        int height = getPreferredSize().height;
        if (img != null) {
            height = (int) (((double) width / img.getWidth()) * img.getHeight());
            if (scale) {
                imageLabel.setIcon(new ImageIcon(img.getScaledInstance(width, height, BufferedImage.SCALE_SMOOTH)));
            } else {
                imageLabel.setIcon(new ImageIcon(img));
            }
        }
        if (width != -1) {
            setSize(width, height);
            setMaximumSize(new Dimension(width, height));
            setMinimumSize(new Dimension(width, height));
            setPreferredSize(new Dimension(width, height));
        }
    }

    @Override
    public void stateChanged() {
    }

    public boolean isScale() {
        return scale;
    }

    public void setScale(boolean scale) {
        this.scale = scale;
    }

    public void setWidth(int width) {
        this.width = width;
        updateImage();
    }

    public void dispose() {
        displayTaskTimer.cancel();
    }

    @Override
    public void acquireImage() {
        camera.acquireImage();
    }
}
